package com.own.demo.blockchain.blockchain2;

import lombok.Data;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

/**
 * @Author liwenfeng
 * @Description dongruan
 * @Date 2023/07/14/20:25
 * @Version 1.0
 */
@Data
public class Block1 {

    // 哈希值，判断挖矿成功与否
    private String hash;
    // 前块哈希值，便于之后验证成功与否
    private String previousHash;
    // 所需存储数据
    private String data;
    // 时间戳
    private long timeStamp;
    // 用于判断挖矿成功的密码学数字。以0开始的随机数
    private int nonce;

    // 构析方法，得到所需信息
    public Block1(String previousHash, String data, long timeStamp) {
        this.previousHash = previousHash;
        this.data = data;
        this.timeStamp = timeStamp;
        this.hash = calculateBlockHash();
    }

    // 得到对应的hash字符串
    // hash算法优势：输出格式一致，而且对数的变化十分敏感，对于之后的验证挖矿成功与否作用巨大！
    public String calculateBlockHash() {
        // 生成独属的字符串，方便之后转换
        String dataToHash = previousHash + Long.toString(timeStamp) + Integer.toString(nonce) + data;
        MessageDigest digest = null;
        byte[] bytes = null;
        try {
            // 创建一个提供信息摘要算法的对象，初始化为SHA-256算法对象
            digest = MessageDigest.getInstance("SHA-256");
            // 用对象调用，信息摘要计算方法，计算后获得字节数组
            // dataToHash.getBytes(StandardCharsets.UTF_8),将字符串转换为字节数组
            // 使用digest()方法生成消息摘要，此方法计算当前对象的散列函数，并以字节数组的形式返回消息摘要
            bytes = digest.digest(dataToHash.getBytes(StandardCharsets.UTF_8));
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        // 用缓存字符串
        StringBuffer buffer = new StringBuffer();
        for (byte b : bytes) {
            // 延伸字符串
            // String.format("%02x",b),以十六进制输出，2为指定的输出字段的宽度，如果为数小于2；则左端补0
            buffer.append(String.format("%02x", b));
        }
        // 返回字符串
        return buffer.toString();
    }


    // 开挖,做工作量证明
    public String minBlock(int prefix) {
        // 创建一个有prefix个的"0"的字符串
        String prefixString = new String(new char[prefix]).replace('\0', '0');
        // 找到开头有prefix多个0的字符串
        // substring方法是，从字符串几位读到几位
        while (!hash.substring(0, prefix).equals(prefixString)) {
            // 决定哪个块
            nonce ++;
            // 通过nonce变化,更新hash值
            hash = calculateBlockHash();
        }
        // 找到了
        // return hash;
        return String.valueOf(nonce);
    }

}

